package codec

import (
	"time"
)

type CodecType uint32

const avCodecTypeMagic = 233333

var (
	H264 = MakeVideoCodecType(avCodecTypeMagic + 1)
	H265 = MakeVideoCodecType(avCodecTypeMagic + 2)

	PCM_MULAW = MakeAudioCodecType(avCodecTypeMagic + 1)
	PCM_ALAW  = MakeAudioCodecType(avCodecTypeMagic + 2)
	AMR_NB    = MakeAudioCodecType(avCodecTypeMagic + 3)
	AMR_WB    = MakeAudioCodecType(avCodecTypeMagic + 4)
	PCM       = MakeAudioCodecType(avCodecTypeMagic + 5)

	// AAC 扩展格式:
	AAC = MakeAudioCodecType(avCodecTypeMagic + 6)

	// SPEEX and NELLYMOSER flash支持的音频:
	SPEEX      = MakeAudioCodecType(avCodecTypeMagic + 7)
	NELLYMOSER = MakeAudioCodecType(avCodecTypeMagic + 8)

	AMR_NB_OPENCORE = MakeAudioCodecType(avCodecTypeMagic + 9)
	AMR_WB_OPENCORE = MakeAudioCodecType(avCodecTypeMagic + 10)
)

func (self CodecType) String() string {
	switch self {
	case H264:
		return "H264"
	case H265:
		return "H265"
	case AMR_NB:
		return "AmrNb"
	case AMR_WB:
		return "AmrWb"
	case AAC:
		return "AAC"
	case SPEEX:
		return "SPEEX"
	case NELLYMOSER:
		return "NELLYMOSER"
	case PCM_MULAW:
		return "PCM_MULAW"
	case PCM_ALAW:
		return "PCM_ALAW"
	case PCM:
		return "PCM"
	}
	return ""
}

func (self CodecType) IsAudio() bool {
	return self&codecTypeAudioBit != 0
}

func (self CodecType) IsVideo() bool {
	return self&codecTypeAudioBit == 0
}

// Make a new video codec type.
func MakeVideoCodecType(base uint32) (c CodecType) {
	c = CodecType(base) << codecTypeOtherBits
	return
}

// Make a new audio codec type.
func MakeAudioCodecType(base uint32) (c CodecType) {
	c = CodecType(base)<<codecTypeOtherBits | CodecType(codecTypeAudioBit)
	return
}

const codecTypeAudioBit = 0x1
const codecTypeOtherBits = 1

// CodecData is some important bytes for initializing audio/video decoder,
// can be converted to VideoCodecData or AudioCodecData using:
//
//	codecdata.(AudioCodecData) or codecdata.(VideoCodecData)
//
// for H264, CodecData is AVCDecoderConfigure bytes, includes SPS/PPS.
type CodecData interface {
	Type() CodecType // Video/Audio codec type
}

type VideoCodecData interface {
	CodecData
	Width() int  // Video width
	Height() int // Video height
}

type AudioCodecData interface {
	CodecData
	SampleFormat() SampleFormat                   // audio sample format
	SampleRate() int                              // audio sample rate
	ChannelLayout() ChannelLayout                 // audio channel layout
	PacketDuration([]byte) (time.Duration, error) // get audio compressed packet duration
}

// some easy codec
type PCMUCodecData struct {
	typ CodecType
}

func (self PCMUCodecData) Type() CodecType {
	return self.typ
}

func (self PCMUCodecData) SampleRate() int {
	return 8000
}

func (self PCMUCodecData) ChannelLayout() ChannelLayout {
	return CH_MONO
}

// 写死s16.
func (self PCMUCodecData) SampleFormat() SampleFormat {
	return S16
}

func (self PCMUCodecData) PacketDuration(data []byte) (time.Duration, error) {
	return time.Duration(len(data)) * time.Second / time.Duration(8000), nil
}

func NewPCMMulawCodecData() AudioCodecData {
	return PCMUCodecData{
		typ: PCM_MULAW,
	}
}

func NewPCMAlawCodecData() AudioCodecData {
	return PCMUCodecData{
		typ: PCM_ALAW,
	}
}
